package com.permissions.dispatcher.processor.util;

import static com.permissions.dispatcher.processor.PermissionsProcessor.TYPE_UTILS;

import com.permissions.dispatcher.annotation.NeedsPermission;
import com.permissions.dispatcher.annotation.OnNeverAskAgain;
import com.permissions.dispatcher.annotation.OnPermissionDenied;
import com.permissions.dispatcher.annotation.OnShowRationale;
import com.permissions.dispatcher.processor.ProcessorUnit;
import com.permissions.dispatcher.processor.exception.WrongClassException;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;

/**
 * 工具类
 */
public class Extensions {
    /**
     * Returns the package name of a TypeElement.
     * @param element element
     * @return str
     */
    public static String packageName(Element element) {
        if (element instanceof TypeElement) {
            return packageName(element.getEnclosingElement());
        } else if (element instanceof PackageElement) {
            return ((PackageElement) element).getQualifiedName().toString();
        } else {
            if ("".equals(packageName(element.getEnclosingElement()))) {
                return "";
            } else {
                return packageName(element.getEnclosingElement());
            }
        }
    }

    /**
     * 清除空格
     * @param str str
     * @return str
     */
    public static String trimDollarIfNeeded(String str) {
        int index = str.indexOf("$");
        if (index == -1) {
            return str;
        } else {
            return str.substring(0, index);
        }
    }

    /**
     * Returns the simple name of an Element as a string.
     * @param element element
     * @return str
     */
    public static String simpleString(Element element) {
        return trimDollarIfNeeded(element.getSimpleName().toString());
    }

    /**
     * Returns the simple name of a TypeMirror as a string.
     * @param typeMirror typeMirror
     * @return str
     */
    public static String simpleString(TypeMirror typeMirror) {
        String toString = typeMirror.toString();
        int indexOfDot = toString.lastIndexOf(".");
        if (indexOfDot == -1) {
            return toString;
        } else {
            return toString.substring(indexOfDot + 1);
        }
    }

    /**
     * Returns whether or not an Element is annotated with the provided Annotation class.
     * @param element e
     * @param annotationType annotationType
     * @return boolean
     */
    public static <T extends Annotation> boolean hasAnnotation(Element element, Class<T> annotationType) {
        return element.getAnnotation(annotationType) != null;
    }

    /**
     * 子childElementsAnnotatedWith
     * @param element element
     * @param annotationClass annotationClass
     * @param <T> <T>
     * @return 集合
     */
    public static <T extends Annotation> List<ExecutableElement> childElementsAnnotatedWith(
            Element element, Class<T> annotationClass) {
        List<ExecutableElement> list = new ArrayList<>();
        for (Element element1 : element.getEnclosedElements()) {
            if (hasAnnotation(element1, annotationClass)) {
                list.add((ExecutableElement) element1);
            }
        }
        return list;
    }

    /**
     * 初始化findAndValidateProcessorUnit
     * @param units units
     * @param element element
     * @param <K> <K>
     * @return ProcessorUnit
     */
    public static <K> ProcessorUnit<K> findAndValidateProcessorUnit(List<ProcessorUnit<K>> units, Element element) {
        TypeMirror typeMirror = element.asType();
        for (ProcessorUnit<K> kal : units) {
            if (isSubtypeOf(typeMirror, kal.getTargetType())) {
                return kal;
            }
        }
        throw new WrongClassException(typeMirror);
    }

    /**
     * 是否子类
     * @param typeMirror typeMirror
     * @param ofType ofType
     * @return boolean
     */
    public static boolean isSubtypeOf(TypeMirror typeMirror, TypeMirror ofType) {
        return TYPE_UTILS.isSubtype(typeMirror, ofType);
    }

    /**
     * 集合转string
     * @param list list
     * @return String
     */
    public static String joinToString(List<String> list) {
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        for (int i = 0; i < list.size(); i++) {
            String sstr = list.get(i);
            builder.append("\"").append(sstr).append("\"");
            if (i != list.size() - 1) {
                builder.append(",");
            }
        }

        builder.append("}");
        return builder.toString();
    }

    /**
     * 注解类型判别
     * @param annotation annotation
     * @return List<String>
     */
    public static List<String> permissionValue(Annotation annotation) {
        if (annotation instanceof NeedsPermission) {
            return Arrays.asList(((NeedsPermission) annotation).value());
        } else if (annotation instanceof OnShowRationale) {
            return Arrays.asList(((OnShowRationale) annotation).value());
        } else if (annotation instanceof OnPermissionDenied) {
            return Arrays.asList(((OnPermissionDenied) annotation).value());
        } else if (annotation instanceof OnNeverAskAgain) {
            return Arrays.asList(((OnNeverAskAgain) annotation).value());
        }
        return new ArrayList<>();
    }
}
